package com.interview.javabase.thread;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author zhangshguang
 * @date 2020/10/21
 */

public class ThreadPoolMonitor extends ThreadPoolExecutor {
    private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolMonitor.class);

    private String poolName;

    private ConcurrentHashMap<String, Date> startTimes;

    public ThreadPoolMonitor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, String poolName) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        this.poolName = poolName;
        this.startTimes = new ConcurrentHashMap<>();
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        startTimes.put(String.valueOf(r.hashCode()), new Date());
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);

        Date start = startTimes.remove(String.valueOf(r.hashCode()));
        Date end = new Date();
        long diff = end.getTime() - start.getTime();
        LOGGER.info("[{}] -pool-monitor Duration:[{}]ms PoolSize:[{}] Active:[{}] Completed:[{}] Task:[{}] Queue:[{}] MaximumPoolSize:[{}]" +
                        "KeepAliveTime:[{}] isShutdown:[{}] isTerminated:[{}]",
                poolName, diff, super.getPoolSize(), super.getActiveCount(), super.getCompletedTaskCount(), super.getTaskCount(),
                super.getQueue().size(), super.getMaximumPoolSize(), super.getKeepAliveTime(TimeUnit.MILLISECONDS), super.isShutdown(), super.isTerminated())
        ;
    }

    public static void main(String[] args) {
        ThreadPoolMonitor threadPoolMonitor = new ThreadPoolMonitor(2, 10, 1, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(4), "testPool");

        for (int i = 0; i < 100; i++) {
            int finalI = i;
            threadPoolMonitor.execute(()->{
                System.out.println(finalI);
            });
        }

    }

}
